﻿using System;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Validation;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using GiveGraphModel;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace ModelTests
{
    /// <summary>
    /// Summary description for UnitTest1
    /// </summary>
    [TestClass]
    public class ModelTest
    {
        public ModelTest()
        {
            //
            // TODO: Add constructor logic here
            //
        }



        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }

        private static GiveGraphContext Context;

        [ClassInitialize()]
        public static void OnInitCreateContext(TestContext t)
        {
            Database.SetInitializer(new DropCreateDatabaseAlways<GiveGraphContext>());
            Context = new GiveGraphContext();

        }

        [ClassCleanup()]
        public static void OnExitDisposeContext()
        {

            Context.Dispose();

        }

        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion

        [TestMethod()]
        public void ShouldCreateAnUserAndGettingIt()
        {
            // constants
            const string zip = "2050";
            const string country = "Portugal";
            const string token = "Token";
            //  Arrange
            var usr = Context.Users.Create();
            usr.ZipCode = zip;
            usr.Country = country;
            usr.FacebookToken = token;

            //  Act
            Context.Users.Add(usr);
            Context.SaveChanges();

            //  Assert
            var users = Context.Users.Where(u => u.ZipCode == zip && u.Country == country && u.FacebookToken == token);
            Assert.IsTrue(users.Count() == 1);
            Assert.AreEqual(usr.MemberId, users.First().MemberId);

        }

        [ExpectedException(typeof(System.Data.Entity.Validation.DbEntityValidationException), AllowDerivedTypes = true)]
        [TestMethod]
        public void ShouldThrowAnExceptionWhenUserConstraintsAreNotValid()
        {
            //  Arrange
            var usr = Context.Users.Create();

            //  Act
            Context.Users.Add(usr);

            try
            {
                Context.SaveChanges();
            }
            catch (DbEntityValidationException)
            {
                Context.Entry(usr).State = EntityState.Unchanged;
                throw;
            }
            
            
            //  Assert
            Assert.Fail("User constraints should have been violated");
        }
        [TestMethod]
        public void AddAnFavoriteOrganizationToAnUserShouldBeVisibleByTheOrganization()
        {
            //  Arrange

            //
            //  Add User
            //
            var usr = Context.Users.Create();
            usr.Country = usr.ZipCode = "..";
            Context.Users.Add(usr);
            //
            //  Add organization
            //
            var org = Context.Organizations.Create();
            org.Name = "org";
            org.FacebookToken = "tt";


            var orgLocation = new Location();
            orgLocation.ZipCode = orgLocation.Country = orgLocation.Address = "..";

            var ol = new OrganizationLocation()
            {
                Description = "base",
                Location = orgLocation,
                Organization = org
            };

            

            var list = new List<OrganizationLocation>() { ol };
            /*
            Context.Entry(org).Collection(o => o.Locations).CurrentValue = list;

            Context.Entry(org).Collection(o => o.Categories).CurrentValue = new List<OrganizationCategory>()
                                                                              {
                                                                                  new OrganizationCategory()
                                                                                      {
                                                                                          Description = "..", 
                                                                                          Name = "ii"
                                                                                      }
                                                                          };*/

            org.Categories = new List<OrganizationCategory>()
                                                                              {
                                                                                  new OrganizationCategory()
                                                                                      {
                                                                                          Description = "..", 
                                                                                          Name = "ii"
                                                                                      }
                                                                 };
            org.Locations = list;     
            Context.Organizations.Add(org);   
            Context.SaveChanges();
            
            
            
            


            //org.Locations.Add(ol);
            //
            //  Insert organization to attach the proxies
            //

            Context.SaveChanges();
            
            

            //  Act
            var persistedUser = Context.Users.Find(usr.MemberId);
            var persistedOrganization = Context.Organizations.Find(org.MemberId);
            persistedUser.FollowingOrganizations.Add(persistedOrganization);
            Context.SaveChanges();
            
            //  Assert

            persistedOrganization = Context.Organizations.Find(org.MemberId);
            persistedUser = Context.Users.Find(usr.MemberId);
            Assert.AreEqual(persistedOrganization.Followers.First().MemberId,persistedUser.MemberId);
            Assert.AreEqual(persistedUser.FollowingOrganizations.First().MemberId,persistedOrganization.MemberId);

        }

        private static User CreateUser(string zipNCoutry)
        {
            var usr = Context.Members.Create<User>();
            usr.FacebookToken = usr.ZipCode = usr.Country = zipNCoutry;
            return usr;
        }

        [TestMethod]
        public void UserShouldBeAbleToProvideResources()
        {
            //
            //  Arrange
            //
            var usr = CreateUser("somestuff");
            try
            {
                Context.Members.Add(usr);
                Context.SaveChanges();
            }
            catch (DbEntityValidationException e)
            {
                
            }
            


            //
            //  Act
            //

            var product = Context.Resources.Create<Product>();
            product.Description = "desc";
            product.Quantity = 2;
            product.ProviderMember = usr;
            Context.Resources.Add(product);
            Context.SaveChanges();
            product.Categories.Add(new ProductCategory(){Description = "...",Name="some"});
            usr.Provides.Add(product);
            Context.SaveChanges();
            //
            //  Assert
            //





        }


        [TestMethod]
        public void __()
        {
            //
            //  Arrange
            //

            //
            //  Act
            //

            //
            //  Assert
            //
        }
    }
}
